package com.superb.common.security.aspect;

import cn.dev33.satoken.stp.StpUtil;
import com.superb.common.core.annotation.SuperbDataScope;
import com.superb.common.core.annotation.SuperbIgnoreTenant;
import com.superb.common.core.enums.DataScope;
import com.superb.common.core.model.Result;
import com.superb.common.security.entity.SuperbUserDataScope;
import com.superb.common.security.feign.RemoteSecuritySystemService;
import com.superb.common.utils.AuthDataScopeUtils;
import com.superb.common.utils.HeardersUtils;
import com.superb.common.utils.SpringContextUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Author: ajie
 * @CreateTime: 2024-07-09 14:07
 */
@Slf4j
@Aspect
@Component
public class SuperbThreadAspect {

    @Resource
    private RemoteSecuritySystemService securitySystemService;

    /**
     * 匹配所有controller下的方法，设置切点
     */
    @Pointcut("execution(* com.superb.*.controller.*.*(..))")
    public void pointcut() {

    }

    /**
     * 处理数据权限仅在controller层设置有效
     * @param joinPoint
     * @throws NoSuchMethodException
     */
    @Before("pointcut()")
    public void beforeControllerMethod(JoinPoint joinPoint) throws NoSuchMethodException {
        /*                        在请求前得到（方法/类）是否自定义数据权限                            */
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取类注解
        Class<?> declaringType = signature.getDeclaringType();
        boolean annotationPresent = declaringType.isAnnotationPresent(SuperbDataScope.class);
        if (annotationPresent) {
            SuperbDataScope annotation = declaringType.getAnnotation(SuperbDataScope.class);
            // 将类上注解赋值
            AuthDataScopeUtils.setDataScopeType(annotation.scope());
        }
        boolean annotationSuperbIgnoreTenant = declaringType.isAnnotationPresent(SuperbIgnoreTenant.class);
        if (annotationSuperbIgnoreTenant) {
            SuperbIgnoreTenant annotation = declaringType.getAnnotation(SuperbIgnoreTenant.class);
            AuthDataScopeUtils.setIsTenant(annotation.value());
        }
        Method method = signature.getMethod();
        Class<?> aClass = joinPoint.getTarget().getClass();
        Method declaredMethod = aClass.getDeclaredMethod(method.getName(), method.getParameterTypes());
        boolean methodAnnotationPresent = declaredMethod.isAnnotationPresent(SuperbDataScope.class);
        if (methodAnnotationPresent) {
            SuperbDataScope annotation = declaredMethod.getAnnotation(SuperbDataScope.class);
            // 将方法上注解赋值
            AuthDataScopeUtils.setDataScopeType(annotation.scope());
        }
        boolean methodAnnotationSuperbIgnoreTenant = declaredMethod.isAnnotationPresent(SuperbIgnoreTenant.class);
        if (methodAnnotationSuperbIgnoreTenant) {
            SuperbIgnoreTenant annotation = declaredMethod.getAnnotation(SuperbIgnoreTenant.class);
            // 将方法上注解赋值
            AuthDataScopeUtils.setIsTenant(annotation.value());
        }
        /*                        在请求前得到方法是否自定义数据权限                            */

        // 未设置权限注解，才进入用户权限
        if (AuthDataScopeUtils.dataScope() == null) {
            HeardersUtils.getOrganizetionId();
            StpUtil.checkLogin();
            // 获取用户当前数据权限范围
            Result<SuperbUserDataScope> scopeResult = securitySystemService.getUserDataScope();
            if (scopeResult.getCode() == 200 && scopeResult.isSuccess()) {
                SuperbUserDataScope data = scopeResult.getResult();
                // 设置数据权限
                DataScope dataScope = DataScope.ofValue(data.getDataScopeType());
                AuthDataScopeUtils.setDataScopeType(dataScope);
            }
        }
    }

    /**
     * 在切点之后执行的操作
     */
    @AfterReturning("pointcut()")
    public void afterControllerMethod() {
        HeardersUtils.clear();
        AuthDataScopeUtils.clear();
    }

}
